using System;
using OracleInternal.Common;

namespace OracleInternal.Network
{
	internal class OraBuf
	{
		internal delegate void AsyncReceiveCallback(OraBuf OB, int length);

		internal static int OAS_StartSize = 2;

		internal byte[] m_buf;

		internal int m_size;

		private int m_cursor;

		internal int m_curlen;

		internal int m_length;

		private int m_ASegs_cursor;

		private OraArraySegment[] m_ASegs = new OraArraySegment[OAS_StartSize];

		private OracleCommunication m_OC;

		internal DataPacket m_packet;

		private OraBuf m_secondary;

		private byte[] m_hdrbuf;

		internal const int RecvSzMultiplier = 4;

		private static object m_sync = new object();

		private static int m_sId;

		internal int m_id;

		internal int the_ByteSegments_Count => m_ASegs_cursor;

		internal OraArraySegment[] the_ByteSegments => m_ASegs;

		internal int size => m_size;

		internal byte[] buf => m_buf;

		internal int cursor => m_cursor;

		internal int Space => m_packet.m_totalLength - m_cursor;

		private OraArraySegment GetNewOAS(byte[] array, int offset, int count)
		{
			if (m_ASegs_cursor >= m_ASegs.Length)
			{
				Array.Resize(ref m_ASegs, m_ASegs.Length * 2);
			}
			OraArraySegment oraArraySegment = m_ASegs[m_ASegs_cursor];
			if (oraArraySegment == null)
			{
				oraArraySegment = (m_ASegs[m_ASegs_cursor] = new OraArraySegment(this, array, offset, count));
			}
			else
			{
				oraArraySegment.OB = this;
				oraArraySegment.Array = array;
				oraArraySegment.Offset = offset;
				oraArraySegment.Count = count;
			}
			m_ASegs_cursor++;
			return oraArraySegment;
		}

		private void Initialize(OracleCommunication OC, int size, bool ReceiveBuf)
		{
			m_OC = OC;
			if (!ReceiveBuf && size > OC.m_sessionCtx.m_sessionDataUnit)
			{
				throw new NetworkException(-6502);
			}
			m_size = size;
			m_packet = new DataPacket(OC.m_sessionCtx, size);
			m_buf = m_packet.m_dataBuffer;
			if (!ReceiveBuf)
			{
				Add(10);
				m_hdrbuf = m_buf;
			}
		}

		internal OraBuf(OracleCommunication OC, int size)
		{
			lock (m_sync)
			{
				m_id = ++m_sId;
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BUF, OracleTraceClassName.OraBuf, OracleTraceFuncName.ctor, "(ALLOCATION) (bufid:" + m_id + ")");
			}
			Initialize(OC, size, ReceiveBuf: false);
		}

		internal OraBuf(OracleCommunication OC, int size, bool ReceiveBuf)
		{
			lock (m_sync)
			{
				m_id = ++m_sId;
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BUF, OracleTraceClassName.OraBuf, OracleTraceFuncName.ctor, "(ALLOCATION) (bufid:" + m_id + ")");
			}
			Initialize(OC, size, ReceiveBuf);
		}

		internal OraBuf(byte[] Buf)
		{
			lock (m_sync)
			{
				m_id = ++m_sId;
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BUF, OracleTraceClassName.OraBuf, OracleTraceFuncName.ctor, "(ALLOCATION) (bufid:" + m_id + ")");
			}
			m_buf = Buf;
		}

		internal void AddForReceive(byte[] buf, int offset, int count)
		{
			GetNewOAS(buf, offset, count);
			m_cursor = offset + count;
			m_length += count;
			m_curlen += count;
		}

		internal void AddForReceive(int offset, int count)
		{
			GetNewOAS(m_buf, offset, count);
			m_cursor = offset + count;
			m_length += count;
			m_curlen += count;
		}

		private void AddIt(OraArraySegment NewAS)
		{
			if (m_curlen + NewAS.Count > m_OC.m_sessionCtx.m_sessionDataUnit)
			{
				InitForSend();
				m_hdrbuf = new byte[TNSPacketOffsets.NSPDADAT];
				m_curlen = 0;
				AddIt(GetNewOAS(m_hdrbuf, 0, TNSPacketOffsets.NSPDADAT));
			}
			m_length += NewAS.Count;
			m_curlen += NewAS.Count;
		}

		internal void Add(byte[] array, int offset, int count)
		{
			if (offset < m_cursor)
			{
				throw new NetworkException(-6501);
			}
			if (offset + count > m_packet.m_totalLength)
			{
				throw new NetworkException(-6502);
			}
			OraArraySegment newOAS = GetNewOAS(array, offset, count);
			m_cursor = offset + count;
			AddIt(newOAS);
		}

		internal void Add(int size)
		{
			Add(m_buf, m_cursor, size);
		}

		internal void InitForSend()
		{
			DataPacket.InitForSend(m_hdrbuf, m_curlen, m_OC.m_sessionCtx);
		}

		internal void ReturnToPool()
		{
			if (m_secondary != null)
			{
				m_OC.OraBufPool.Put(m_secondary.size, m_secondary);
				m_secondary = null;
			}
			m_OC.OraBufPool.Put(size, this);
		}

		internal void Clear()
		{
			m_ASegs_cursor = 0;
			m_length = 0;
			m_cursor = 0;
			m_curlen = 0;
			m_hdrbuf = m_buf;
			if (m_secondary != null)
			{
				m_secondary.Clear();
			}
		}

		internal void ReInit(bool forReceive)
		{
			Clear();
			if (!forReceive)
			{
				Add(10);
			}
		}
	}
}
